<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <title>单位圆与三角函数曲线演示</title>
  <style>
    body {
      display: flex;
      flex-direction: column;
      align-items: center;
      background: #111;
      color: #eee;
      font-family: sans-serif;
    }

    .controls {
      margin: 10px;
    }

    .row {
      display: flex;
      gap: 20px;
    }

    canvas {
      background: #000;
      border: 1px solid #444;
    }

    input[type=range] {
      width: 400px;
    }

    button {
      margin-left: 10px;
      padding: 5px 15px;
      background: #333;
      color: #eee;
      border: 1px solid #666;
      border-radius: 5px;
      cursor: pointer;
    }

    button:hover {
      background: #555;
    }

    .legend {
      margin-top: 10px;
      display: flex;
      flex-wrap: wrap;
      gap: 10px;
    }

    .legend-item {
      display: flex;
      align-items: center;
      gap: 5px;
    }

    .color-box {
      width: 15px;
      height: 15px;
    }

    .graphs {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 15px;
      margin-top: 15px;
    }
  </style>
</head>

<body>
  <h2>单位圆与三角函数周期演示</h2>

  <div class="controls">
    <label>θ角度: <span id="angleValue">45</span>°</label>
    <button id="playBtn">▶ 自动播放</button>
    <input type="range"
      id="angle"
      min="0"
      max="360"
      value="45">
    <div class="legend"
      id="legend"></div>
  </div>

  <div class="row">
    <canvas id="circleCanvas"
      width="500"
      height="500"></canvas>
    <canvas id="graphCanvas"
      width="600"
      height="500"></canvas>


  </div>

  <div class="graphs">
    <canvas id="sinGraph"
      width="300"
      height="200"></canvas>
    <canvas id="cosGraph"
      width="300"
      height="200"></canvas>
    <canvas id="tanGraph"
      width="300"
      height="200"></canvas>
    <canvas id="cotGraph"
      width="300"
      height="200"></canvas>
    <canvas id="secGraph"
      width="300"
      height="200"></canvas>
    <canvas id="cscGraph"
      width="300"
      height="200"></canvas>
  </div>

  <script>
    const circleCanvas = document.getElementById("circleCanvas");
    const ctxC = circleCanvas.getContext("2d");

    const slider = document.getElementById("angle");
    const angleValue = document.getElementById("angleValue");
    const playBtn = document.getElementById("playBtn");
    const graphCanvas = document.getElementById("graphCanvas");
    const ctxG = graphCanvas.getContext("2d");
    // 绘制函数曲线
    function drawGraphs(theta) {
      ctxG.clearRect(0, 0, graphCanvas.width, graphCanvas.height);

      // 坐标轴
      ctxG.strokeStyle = "#888";
      ctxG.beginPath();
      ctxG.moveTo(50, 250);
      ctxG.lineTo(550, 250);
      ctxG.moveTo(300, 0);
      ctxG.lineTo(300, 500);
      ctxG.stroke();

      // θ映射到画布x
      function xMap(t) { return 50 + (t / 360) * 500; }
      function yMap(val) { return 250 - val * 40; }

      const funcs = {
        sin: Math.sin,
        cos: Math.cos,
        tan: Math.tan,
        cot: t => 1 / Math.tan(t),
        sec: t => 1 / Math.cos(t),
        csc: t => 1 / Math.sin(t)
      };

      for (let key in funcs) {
        ctxG.strokeStyle = colors[key];
        ctxG.beginPath();
        let first = true;
        for (let t = 0; t <= 360; t += 1) {
          let rad = t * Math.PI / 180;
          let val = funcs[key](rad);
          if (Math.abs(val) > 10) { // 避免无限大
            first = true;
            continue;
          }
          let x = xMap(t);
          let y = yMap(val);
          if (first) {
            ctxG.moveTo(x, y);
            first = false;
          } else {
            ctxG.lineTo(x, y);
          }
        }
        ctxG.stroke();
      }

      // 高亮当前点
      for (let key in funcs) {
        let rad = theta * Math.PI / 180;
        let val = funcs[key](rad);
        if (Math.abs(val) > 10) continue;
        ctxG.fillStyle = colors[key];
        ctxG.beginPath();
        ctxG.arc(xMap(theta), yMap(val), 4, 0, 2 * Math.PI);
        ctxG.fill();
      }
    }

    const R = 200; // 单位圆缩放
    const OX = 250, OY = 250;
    let isPlaying = false;
    let currentAngle = 45;
    let timer = null;

    const colors = {
      sin: "orange",
      cos: "cyan",
      tan: "red",
      cot: "pink",
      sec: "violet",
      csc: "lime"
    };

    const funcs = {
      sin: Math.sin,
      cos: Math.cos,
      tan: Math.tan,
      cot: t => 1 / Math.tan(t),
      sec: t => 1 / Math.cos(t),
      csc: t => 1 / Math.sin(t)
    };

    // === 添加图例 ===
    const legendDiv = document.getElementById("legend");
    Object.keys(colors).forEach(key => {
      const item = document.createElement("div");
      item.className = "legend-item";
      item.innerHTML = `<div class="color-box" style="background:${colors[key]}"></div>${key}(θ)`;
      legendDiv.appendChild(item);
    });

    // === 绘制单位圆 ===
    function drawCircle(theta) {
      ctxC.clearRect(0, 0, circleCanvas.width, circleCanvas.height);

      // 坐标轴
      ctxC.strokeStyle = "#888";
      ctxC.beginPath();
      ctxC.moveTo(0, OY);
      ctxC.lineTo(circleCanvas.width, OY);
      ctxC.moveTo(OX, 0);
      ctxC.lineTo(OX, circleCanvas.height);
      ctxC.stroke();

      // 单位圆
      ctxC.strokeStyle = "#0f0";
      ctxC.beginPath();
      ctxC.arc(OX, OY, R, 0, 2 * Math.PI);
      ctxC.stroke();

      // P 点
      let rad = theta * Math.PI / 180;
      let Px = OX + R * Math.cos(rad);
      let Py = OY - R * Math.sin(rad);

      ctxC.strokeStyle = "#fff";
      ctxC.beginPath();
      ctxC.moveTo(OX, OY);
      ctxC.lineTo(Px, Py);
      ctxC.stroke();

      ctxC.fillStyle = "yellow";
      ctxC.beginPath();
      ctxC.arc(Px, Py, 5, 0, 2 * Math.PI);
      ctxC.fill();

      let cosT = Math.cos(rad), sinT = Math.sin(rad);

      // === sinθ ===
      ctxC.strokeStyle = colors.sin;
      ctxC.beginPath();
      ctxC.moveTo(Px, Py);
      ctxC.lineTo(Px, OY);
      ctxC.stroke();

      // === cosθ ===
      ctxC.strokeStyle = colors.cos;
      ctxC.beginPath();
      ctxC.moveTo(Px, Py);
      ctxC.lineTo(OX, Py);
      ctxC.stroke();

      // === tanθ ===
      if (Math.abs(cosT) > 1e-6) {
        let Xt = OX + R * (1 / cosT);
        let Yt = OY;
        ctxC.strokeStyle = colors.tan;
        ctxC.beginPath();
        ctxC.moveTo(Px, Py);
        ctxC.lineTo(Xt, Yt);
        ctxC.stroke();
      }

      // === cotθ ===
      if (Math.abs(sinT) > 1e-6) {
        let Xc = OX;
        let Yc = OY - R * (1 / sinT);
        ctxC.strokeStyle = colors.cot;
        ctxC.beginPath();
        ctxC.moveTo(Px, Py);
        ctxC.lineTo(Xc, Yc);
        ctxC.stroke();
      }

      // === secθ ===
      if (Math.abs(cosT) > 1e-6) {
        let Xs = OX + R * (1 / cosT);
        ctxC.strokeStyle = colors.sec;
        ctxC.beginPath();
        ctxC.moveTo(OX, OY);
        ctxC.lineTo(Xs, OY);
        ctxC.stroke();
      }

      // === cscθ ===
      if (Math.abs(sinT) > 1e-6) {
        let Yc = OY - R * (1 / sinT);
        ctxC.strokeStyle = colors.csc;
        ctxC.beginPath();
        ctxC.moveTo(OX, OY);
        ctxC.lineTo(OX, Yc);
        ctxC.stroke();
      }
    }

    // === 绘制单个函数图 ===
    function drawGraph(canvasId, funcKey, theta) {
      const canvas = document.getElementById(canvasId);
      const ctx = canvas.getContext("2d");
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      const width = canvas.width, height = canvas.height;
      const originX = 50, originY = height / 2;

      // 坐标轴
      ctx.strokeStyle = "#888";
      ctx.beginPath();
      ctx.moveTo(0, originY);
      ctx.lineTo(width, originY);
      ctx.moveTo(originX, 0);
      ctx.lineTo(originX, height);
      ctx.stroke();

      function xMap(t) { return originX + (t / 360) * (width - 60); }
      function yMap(val) { return originY - val * 40; }

      const f = funcs[funcKey];
      ctx.strokeStyle = colors[funcKey];
      ctx.beginPath();
      let first = true;
      for (let t = 0; t <= 360; t += 1) {
        let rad = t * Math.PI / 180;
        let val = f(rad);
        if (Math.abs(val) > 10) { first = true; continue; }
        let x = xMap(t), y = yMap(val);
        if (first) { ctx.moveTo(x, y); first = false; }
        else { ctx.lineTo(x, y); }
      }
      ctx.stroke();

      // 高亮点
      let rad = theta * Math.PI / 180;
      let val = f(rad);
      if (Math.abs(val) <= 10) {
        ctx.fillStyle = colors[funcKey];
        ctx.beginPath();
        ctx.arc(xMap(theta), yMap(val), 4, 0, 2 * Math.PI);
        ctx.fill();
      }

      // 标题
      ctx.fillStyle = "#fff";
      ctx.fillText(funcKey + "(θ)", width / 2 - 20, 15);
    }

    function drawAll(theta) {
      drawCircle(theta);
      drawGraphs(theta);
      drawGraph("sinGraph", "sin", theta);
      drawGraph("cosGraph", "cos", theta);
      drawGraph("tanGraph", "tan", theta);
      drawGraph("cotGraph", "cot", theta);
      drawGraph("secGraph", "sec", theta);
      drawGraph("cscGraph", "csc", theta);
    }

    slider.oninput = function () {
      currentAngle = +this.value;
      angleValue.innerText = currentAngle;
      drawAll(currentAngle);
    };

    playBtn.onclick = function () {
      if (!isPlaying) {
        isPlaying = true;
        playBtn.innerText = "⏸ 暂停";
        timer = setInterval(() => {
          currentAngle = (currentAngle + 1) % 360;
          slider.value = currentAngle;
          angleValue.innerText = currentAngle;
          drawAll(currentAngle);
        }, 50);
      } else {
        isPlaying = false;
        playBtn.innerText = "▶ 自动播放";
        clearInterval(timer);
      }
    };

    drawAll(currentAngle);


  </script>
</body>

</html>